
use Digest::MD5 qw(md5 md5_hex md5_base64);

my $INDEX_FILE = '../index.html';
my $BUILD_DIR  = 'build';
my $SECRET_KEY = '-';
my $DEPLOY_URL = '-';
my $JSCOMPILER = 'gcc-20110615.jar';

my $params = (join " ", @ARGV);
%publish_params = (
  'production' => !($params !~ /(^|\s)-(production)(\s|$)/),
  'pack'    => !($params !~ /(^|\s)-(pack|publish)(\s|$)/),
  'archive' => !($params !~ /(^|\s)-(archive|publish)(\s|$)/),
  'clear'   => !($params !~ /(^|\s)-(clear|publish)(\s|$)/),
  'deploy'  => !($params !~ /(^|\s)-(deploy|publish)(\s|$)/),
);

if ($publish_params{'production'})
{
  #$SECRET_KEY = '';
}

my @dp = (gmtime(time))[5, 4, 3, 2, 1];
$dp[0] += 1900;
$dp[1] += 1;
my $label = sprintf('%02d%02d%02d%02d%02d', @dp);
print "BUILD: $label\n".('='x40)."\n\n";

mkdir $BUILD_DIR;

open F, $INDEX_FILE;
read F, $buf, -s F;
close F;

$buf =~ s/<!--[^\[](.|\n\r)+?-->//gs;
$buf =~ s/<script\s+type="text\/javascript"\s+src="([^"]+)"><\/script>\s*|<link(?:\s+id="[^"]+")?\s+rel="stylesheet"\s+type="text\/css"\s+title="Default Style"\s+href="([^"]+?)"(?:\s+media="[^"]+")?/
  if ($2)
  {
    push @cssfiles, $2;
    $&;
  }
  else
  {
    push @files, "..\/$1";
    $&;
  }
/meig;

print "CSS:\n====\n";

mkdir "$BUILD_DIR/res";

my %resources = ();
my $total_init_css_size = 0;
my $total_final_css_size = 0;
my $total_res_size = 0;
my $CSS_FILE_STAT = {};
for $cssfile (@cssfiles)
{
print "$cssfile\n";
  print "\n  # $cssfile\n";
  open F, "../$cssfile";
  read F, $cssbuf, -s F;
  $total_init_css_size += -s F;
  close F;
  $cssbuf =~ s~url\((([\"\']?)data:[^\)]+?\2)\)~url[$1]~gi; 
  $cssbuf =~ s~url\(([\'\"]?)([^\)]+)\1\)~url(../app/_style\/$2)~g;
  my $import_count = 0;
  while ($cssbuf =~ s/\s+(\@import\s+'((\.\.\/\.\.\/)?([^']*?)[^\/\\\']+\.css)(?:\?[^']*)?';)/
    $import_count++;
    print "    + $1 \n";

    my $css_path = $4;
    my $path = ($3 ? '..\/' : '') . $4;
    if (!$3)
    {
      if ($path =~ s~^\.\.\/~~)
      {
        $path = '..\/app\/' . $path;
      }
      else
      {
        $path = "..\/app\/_style\/" . $path;
      }
    }

    my $fn = "..\/app\/_style\/$2";
    open F, $fn;
    read F, $css, -s F;
    $total_init_css_size += -s F;
    close F;

    $css =~ s~\@import\s+\'([^']+?)\'~\@import '$css_path$1'~g;
    $css =~ s~url\((([\"\']?)data:[^\)]+?\2)\)~url[$1]~gi; 
    $css =~ s~url\(([\'\"]?)([^\)]+?)\1\)~url($path$2)~g;

    "\n\n  \/* $fn *\/\n$css";
  /ei)
  {
  }

  while ($cssbuf =~ s<[\@a-z0-9\_]+\/\.\.\/><>gi){}
  $cssbuf =~ s<url\(\.\.\/basis><url(basis>g;
  $cssbuf =~ s<url\(([^\)]+)\)><$resources{(substr($1, 0, 5) eq "basis" ? '../../' : '') . $1}++;"$&">ge;
  $cssbuf =~ s<url\[([^\]]+)\]><url($1)>g;

  print "\n    RESOURCES:\n";
  for my $resource (sort { -s "$a" <=> -s "$b" } keys %resources)
  {
    next if $resources{$resource} !~ /^\d+$/;

    ($file = $resource) =~ s/#[a-z\_]+$//;
    $file =~ /\.([a-z]+)$/;
    my $ext = $1;

    unless (-e $file)
    {
      print "$file - not found\n";
      $resources{$resource} = "#";
      next;
    }

    open RES, $file;
    binmode RES;
    read RES, my $res, -s RES;
    $total_res_size += -s RES;
    close RES;

    #my $md5 = md5_hex($res);
    my $md5b = md5_base64($res);
    $md5b =~ tr/\/\+/\_\-/;  # web safe
    my $new_filename = "$md5b.$ext";

    print sprintf("%10d", -s "$file") . "\t$resources{$resource}\t$md5b\t$resource";
    if (-e "$BUILD_DIR/res/$new_filename")
    {
      print " [exists]";
    }
    else
    {
      open RES, ">$BUILD_DIR/res/$new_filename";
      binmode RES;
      print RES $res;
      close RES;
    }
    print "\n";

    $resources{$resource} = "res/$new_filename";
  }

  $cssbuf =~ s/url\(([^\)]+?(\#[a-z0-9\_]+)?)\)/'url(' . ($resources{$1} || $resources{"..\/$1"} || $1) . "$2)"/ge;

  #$cssfile =~ /[^\/\\]+\.css$/;
  my @path_parts = split /[\\\/]/, $cssfile;
  shift @path_parts;
  shift @path_parts;
  my $newname = join '_', @path_parts;
  open F, ">$BUILD_DIR/$newname";
  print F $cssbuf;
  close F;

  # pack css
  my $css_filesize = 0;
  if ($publish_params{'pack'})
  {
    my $filename = "$BUILD_DIR/$newname";
    print "    Pack $newname";
    my $packed_css;
    my $old_size = -s $filename;
    `java -jar yuicompressor-2.4.2.jar $filename -o $filename`;

    # fix for @media rules
    open FM, $filename;
    read FM, $packed_css, -s FM;
    close FM;
    $packed_css =~ s/and\(/and (/g;
    open FM, ">$filename";
    print FM $packed_css;
    close FM;
    # fix end

    print " - ok [size: $old_size -> " . (-s $filename) . "]\n";
    $total_final_css_size += ($css_filesize = -s $filename);
  }
  else
  {
    $total_final_css_size += ($css_filesize = length $cssbuf);
  }

  $CSS_FILE_STAT->{$newname} = {
    import_count => $import_count,
    filesize => $css_filesize
  };
  
  $buf =~ s/href="$cssfile"/href="$newname?$label"/;
}

print "\nCSS stat:\n=========\n";
for my $cssfile (keys %$CSS_FILE_STAT){
  print sprintf(" %20s: %6d bytes (%2d files merged)\n", $cssfile, $CSS_FILE_STAT->{$cssfile}->{filesize}, $CSS_FILE_STAT->{$cssfile}->{import_count} + 1);
}

$buf =~ s/(\s+<script type="text\/javascript" src="\.\.\/basis[^"]+\.js(?:\.bak)?"><\/script>[\r\n]+)+/\n\n  <script type="text\/javascript" src="basis.js?$label"><\/script>\n\n/;

my @basis_modules;
if ($buf =~ /var basis_modules = \(?"([^"]+)"/)
{
  @basis_modules = split /\s+/, $1;
}

my @modules;
if ($buf =~ /var modules = \(?"([^"]+)"/)
{
  @modules = split /\s+/, $1;
  for (@modules)
  {
    push @files, "../app/$_/script.js";
  }

  #$buf =~ s/<!-- cabinet modules -->.+<!-- \/cabinet modules -->/<script type="text\/javascript" src="cabinet.js?$label"><\/script>/;
}

if ($buf =~ /var app_commons = \(?"([^"]+)"/)
{
  my @tmp = split /\s+/, $1;
  for (@tmp)
  {
    push @modules, "app_common/$_";
    push @files, "../app/app_common/$_/script.js";
  }

  #$buf =~ s/<!-- cabinet modules -->.+<!-- \/cabinet modules -->/<script type="text\/javascript" src="cabinet.js?$label"><\/script>/;
}
$buf =~ s/<script type="text\/javascript" src="app\/\S+\.js"><\/script>[\r\n\s]+<script (.|[\r\n])+<\/script>/<script type="text\/javascript" src="app.js?$label"><\/script>/;
#$buf =~ s/(document\.write\(')(<script type="text\/javascript" src=")app\/\@locale\/.+?\/main\.js/${1}${2}locale_base.js?$label"><\\\/script>/;
$buf =~ s/src="app\/\@locale\/base\/main\.js"/src="locale_base.js?$label"/;
$buf =~ s/src="app\/\@locale\/' \+ Locale\.lang \+ '\/main\.js"/src="locale_' + Locale.lang + '.js?$label"/;
$buf =~ s/\s+\(function\(\)\{(.|[\r\n])+\}\)\(\);\s+/\n\n    /;


opendir L, '../app/@locale';
my @locales = grep { !-d && !/\.\.?/ } readdir L;
closedir L;

my @scripts = ();
my %charset = (
#  ru => 'cp1251'
);

  use Encode qw(encode decode);
  sub to_utf{
    my $locale = $_[0];
    if ($charset{lc $locale})
    {
      return decode($charset{lc $locale}, $_[1]);
    }
    else
    {
      return $_[1];
    }
  }

print "\nLOCALE:\n=======\n";
push @modules, 'main';
for my $locale (@locales)
{
  print "\n  " . uc($locale) . ": ";
  my $script_filename = "$BUILD_DIR/locale_$locale.js";
  push @scripts, $script_filename;
  open LF, ">$script_filename";
  binmode(LF, ":utf8") if $charset{lc $locale};
  for my $mod (@basis_modules)
  {
    open LFJS, "../../basis/locale/$locale/$mod.js";
    read LFJS, my $text, -s LFJS;
    close LFJS;
    $text =~ s/^[^\sa-z]..//i;
    print LF "\n  // basis/locale/$locale/$mod.js\n\n";
    print LF to_utf($locale, $text);
    print LF "\n";
    print " basis/$mod";
  }
  for my $mod (@modules)
  {
    open LFJS, "../app/\@locale/$locale/$mod.js";
    read LFJS, my $text, -s LFJS;
    close LFJS;
    $text =~ s/^[^\sa-z]..//i;
    print LF "\n  // app/\@locale/$locale/$mod.js\n";
    print LF to_utf($locale, $text);
    print " $mod";
  }
  close LF;
}

print "\n\nCOPY STATIC FILES:\n==================\n\n";

for my $locale (@locales)
{
  if (-e "../app/\@locale/$locale/help")
  {
    print "  $locale: copy help files";
    mkdir "$BUILD_DIR/res/$locale";
    #mkdir "$BUILD_DIR/res/$locale/help";
    #mkdir "$BUILD_DIR/res/$locale/help/img";
    `xcopy ..\\app\\\@locale\\$locale $BUILD_DIR\\res\\$locale /S /Y 2>&1`;
    unlink <$BUILD_DIR\\res\\$locale\\*.js>;
    #`copy cabinet\\locale\\$locale\\help\\* $BUILD_DIR\\res\\$locale\\help 2>&1`;
    #`copy cabinet\\locale\\$locale\\help\\img\\* $BUILD_DIR\\res\\$locale\\help\\img 2>&1`;
    print " - done\n";
  }
}

mkdir "$BUILD_DIR/res/swf";
print "  copy swf files";
`xcopy ..\\app\\\_swf $BUILD_DIR\\res\\swf /S /Y 2>&1`;
print " - done\n";

mkdir "$BUILD_DIR/res/static";
print "  copy static files";
`xcopy ..\\app\\\_static $BUILD_DIR\\res\\static /S /Y 2>&1`;
print " - done\n";

print "  copy cache manifest";
#`xcopy ..\\app.cache-manifest $BUILD_DIR /Y 2>&1`;
open CN, '../app.cache-manifest';
read CN, $cache_buf, -s CN;
close CN;
$cache_buf =~ s/\[version\]/$label/g;
open CN, ">$BUILD_DIR/app.cache-manifest";
print CN $cache_buf;
close CN;
print " - done\n";

print "\nJAVASCRIPT:\n===========\n\n";

open BASIS, ">$BUILD_DIR/basis.js";
#binmode BASIS, ':utf8';
open CABINET, ">$BUILD_DIR/app.js";
#binmode CABINET, ':utf8';
my $total_init_js_size = 0;
my $total_finaly_js_size = 0;
for (@files)
{
  open F, $_;
  read F, $jsbuf, -s F;
  $total_init_js_size += -s F;
  close F;

  $jsbuf =~ s[app\/common\/flags][res\/flags]g;
  $jsbuf =~ s[app\/\@locale][res]g;
  $jsbuf =~ s[app\/\_swf][res\/swf]g;
  $jsbuf =~ s[app\/\_static][res\/static]g;
  $jsbuf =~ s[/cgi-bin/w1/get_help.cgi][/cgi-bin/get_help.cgi]g;
  $jsbuf =~ s[/cgi-bin/raw_to_csv.pl][/cgi-bin/report.cgi]g;
  $jsbuf = to_utf('ru', $jsbuf);

  if (/^(\.\.\/)*basis/)
  {
    print BASIS "\n\n// $_\n";
    print BASIS $jsbuf;
    print "  add to basis.js";
  }
  else
  {
    print CABINET "\n\n// $_\n";
    print CABINET $jsbuf;
    print "  add to app.js";
  }

  print "\t $_\n";
}
close CABINET;
close BASIS;

push @scripts, "$BUILD_DIR/basis.js";
push @scripts, "$BUILD_DIR/app.js";

print "\n  basis.js: " .   (-s "$BUILD_DIR/basis.js");
print "\n  app.js: " . (-s "$BUILD_DIR/app.js");

if ($publish_params{'pack'})
{
  print "\n\nPACK JAVASCRIPT:\n================\n\n";
  for $script (@scripts)
  {
    print "  pack $script";
    my $old_size = -s $script;


    open F, $script;
    binmode F;
    read F, my $buf, -s $script;
    close F;

    $buf =~ s/^\s*;;;.+$//gm;
    $buf =~ s/\/\*\*\s*\@cut.*?\*\/.+$//gm;

    open F, ">$script";
    binmode F;
    print F $buf;
    close F;

    if ($script =~ /locale_/)
    {
      `java -jar yuicompressor-2.4.2.jar --charset utf8 $script -o $script`;
    }
    else
    {
      `java -jar $JSCOMPILER --js $script --js_output_file $script.packed`;
      unlink <$script>;
      rename "$script.packed", "$script";
    }
    #`"C:\\Documents and Settings\\lahmatiy\\Local Settings\\Application Data\\Google\\Chrome\\Application\\chrome.exe" --user-data-dir=c:/temp/chrome --app=http://local.ru/w1client/Cabinet2.0/packjs.html?$script`;
    print " - ok [size: $old_size -> " . (-s $script) . "]\n";
  }
}

print "\n\nADD HEADERS TO JAVASCRIPT:\n==========================\n\n";

my $basis_header, $app_header, $locale_header;
open FH, '_basis.header';
read FH, $basis_header, -s FH;
close FH;
open FH, '_app.header';
read FH, $app_header, -s FH;
close FH;
open FH, '_locale.header';
read FH, $locale_header, -s FH;
close FH;

my $filename = "$BUILD_DIR/basis.js";
print "  $filename";
my $old_size = -s $filename;
open BASIS, $filename;
#binmode BASIS, ':utf8';
read BASIS, my $code, -s BASIS;
close BASIS;
open BASIS, ">$filename";
#binmode BASIS, ':utf8';
print BASIS $basis_header; # print BASIS HEADER
print BASIS $code;
close BASIS;
print " - ok [size: $old_size -> " . (-s $filename) . "]\n";
$total_finaly_js_size += -s $filename;

my $filename = "$BUILD_DIR/app.js";
print "  $filename";
my $old_size = -s $filename;
open CABINET, $filename;
#binmode CABINET, ':utf8';
read CABINET, my $code, -s CABINET;
close CABINET;
open CABINET, ">$filename";
#binmode CABINET, ':utf8';
print CABINET $app_header; # print APP HEADER
print CABINET $code;
close CABINET;
print " - ok [size: $old_size -> " . (-s $filename) . "]\n";
$total_finaly_js_size += -s $filename;

for $script (@scripts)
{
  next if $script !~ /locale_([a-z]+)\.js$/;

  my $locale = uc $1;

  my $old_size = -s $script;
  print "  $script";
  open S, $script;
  binmode S, ':utf8';
  read S, my $code, -s S;
  close S;
  open S, ">$script";
  binmode S, ':utf8';
  ($th = $locale_header) =~ s/\$locale\$/$locale/;
  print S $th;
  print S $code;
  close S;
  print " - ok [size: $old_size -> " . (-s $script) . "]\n";

}

print "\nTOTALS:\n=======\n\n";
print "  css: $total_final_css_size ($total_init_css_size)\n";
print "  css resources: $total_res_size\n";
print "  javascript: $total_finaly_js_size ($total_init_js_size)\n";

print "\nREBUILD INDEX:\n==============\n\n  index.html";

$buf =~ s/windows-1251/utf-8/gi;

open F, ">$BUILD_DIR/index.html";
#binmode F, ':utf8';
#$buf =~ s/(<html[^>]+)>/$1 manifest="app.cache-manifest">/;
if (1 || $publish_params{'production'})
{
  $buf =~ s/<\/title>/$&\n  <meta name="build" content="$label" \/>/i;
}
else
{
  $buf =~ s/<title>([^<]+)<\/title>/<title>$1 (build $label)<\/title>/i;
}
$buf =~ s[app/\_static/][res/static/]g;
print F to_utf('ru', $buf);
close F;

print " - ok\n";

if ($publish_params{'archive'})
{
  print "\nCREATE AN ARCHIVE:\n==================\n\n";
  print "  create $BUILD_DIR.zip";
  use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
  my $zip = Archive::Zip->new();
  $zip->addTree($BUILD_DIR, '');
  if ($zip->writeToFileNamed("$BUILD_DIR.zip") == AZ_OK)
  {
    print " - ok\n";
  }
  else
  {
    print " - zip write error\n";
  }

  if ($publish_params{'clear'})
  {
    print "  delete all temp files";
    `rmdir $BUILD_DIR /S /Q`;
    print " - ok\n";
  }

  if ($publish_params{'deploy'})
  {
    print "\nDEPLOY ON SERVER:\n=================\n\n";

    print "  upload archive\n";

    use LWP::UserAgent;

    open F, "$BUILD_DIR.zip";
    binmode F;
    read F, my $data, -s F;
    close F;

    my $ua = LWP::UserAgent->new;
    #$ua->timeout(10);

    #my $response = $ua->post();

    my $req = HTTP::Request->new(POST => $DEPLOY_URL . $SECRET_KEY);
    $req->content_type('octet-stream');
    $req->content($data);
    # Pass request to the user agent and get a response back
    my $res = $ua->request($req);
    # Check the outcome of the response
    unless ($res->is_success) {
        print "    ".$res->status_line . "\n";
    }
    my $response = $res->content;
    $response =~ s/\r\n?|\n\r?/$&    /g;
    print "    ".$response."\n";

    if ($publish_params{'clear'})
    {
      unlink "$BUILD_DIR.zip";
    }
  }
}

print "\nBUILD COMPLETE";